package deferx

import (
	"fmt"

	"std/abcx"

	"github.com/gookit/color"
)

// deferx 函數在執行到 deferx 語句 那一刻，它的內容就已確定 // 保存整個表達式
type deferProblem struct {
}

func (r deferProblem) AA() {
	defer func() { color.Redln("1 before") }()
	defer func() { color.Redln("2 ing") }()
	defer func() { color.Redln("3 after") }()
	panic("err") // 3 2 1 err
}

func (r deferProblem) CC() {
	i := 1
	stu := abcx.Person{Name: "stu", Age: i}
	stu2 := &abcx.Person{Name: "stu2", Age: i} //  指針
	defer color.Redln(i, ":", stu, ":", stu2)  //deferx 時計算，之後更改不會影響,除非指針
	i++
	stu.Age += 10
	stu2.Age += 10
	color.Redln("CC", i, ":", stu, ":", stu2)
}
func (r deferProblem) DD() {
	i := 1
	stu := abcx.Person{Name: "stu", Age: i}
	stu2 := &abcx.Person{Name: "stu2", Age: i}             //  指針
	defer func() { color.Redln(i, ":", stu, ":", stu2) }() // 是保存整個表達式，不是具體值
	i++
	stu.Age += 10
	stu2.Age += 10
	color.Redln("DD", i, ":", stu, ":", stu2) //deferx 時計算，之後更改不會影響,除非指針
}

func (r deferProblem) EE() {
	i := 1
	stu := abcx.Person{Name: "stu", Age: i}
	stu2 := &abcx.Person{Name: "stu2", Age: i}
	defer func(i int, stu abcx.Person, age2 *abcx.Person) {
		i++ // 位置不影響
		stu.Age += 10
		age2.Age += 10
		color.Greenln("second", i, ":", stu, ":", stu2)
	}(
		i, stu, stu2,
	)
	color.Greenln("first ", i, ":", stu, ":", stu2)
	return
}
func (r deferProblem) FF() {
	te := func() { color.Redln("..1") }
	defer te()
	te = func() { color.Greenln("..2") }
	defer te()
}
func (r deferProblem) GG() {
	i := uint32(1)
	defer func(i uint32) {
		fmt.Println("1", i)
	}(i)
	i++
	defer func(i uint32) {
		fmt.Println("2", i)
	}(i)
	i++
	defer func(i uint32) {
		fmt.Println("3", i)
	}(i)
	panic("err") // 之後無法執行到，但之前的fefer會被執行
	defer func(i uint32) {
		fmt.Println("4", i)
	}(i)
}

/*
异常的使用场景简单描述：Go中可以抛出一个panic的异常，然后在defer中通过recover捕获这个异常，然后正常处理。

panic：
    1、内置函数
    2、假如函数F中书写了panic语句，会终止其后要执行的代码，在panic所在函数F内如果存在要执行的defer函数列表，按照defer的逆序执行
    3、返回函数F的调用者G，在G中，调用函数F语句之后的代码不会执行，假如函数G中存在要执行的defer函数列表，按照defer的逆序执行
    4、直到goroutine整个退出，并报告错误
recover：
    1、内置函数
    2、用来控制一个goroutine的panicking行为，捕获panic，从而影响应用的行为
    3、一般的调用建议
        a). 在defer函数中，通过recever来终止一个goroutine的panicking过程，从而恢复正常代码的执行
        b). 可以获取通过panic传递的error
注意:

    1.利用recover处理panic指令，defer 必须放在 panic 之前定义，另外 recover 只有在 defer 调用的函数中才有效。否则当panic时，recover无法捕获到panic，无法防止panic扩散。
    2.recover 处理异常后，逻辑并不会恢复到 panic 那个点去，函数跑到 defer 之后的那个点。
    3.多个 defer 会形成 defer 栈，后定义的 defer 语句会被最先调用。
*/
